﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Dycox.Reporting.Aggregation;
using Dycox.Linq;

namespace Dycox.Reporting
{
    public abstract class AggregationContext
    {
        public AggregationContext(string dataMember)
        {
            if (dataMember == null && RequiresDataMember)
                throw new ArgumentNullException("dataMember");
            
            _dataMember = dataMember;
        }

        protected virtual bool RequiresDataMember
        {
            get { return true; }
        }

        private string _dataMember;

        public string DataMember
        {
            get { return _dataMember; }
        }

        private PropertyDescriptor _property;

        public PropertyDescriptor Property
        {
            get { return _property; }
        }

        private bool _isAggregating;

        public bool IsAggregating
        {
            get { return _isAggregating; }
        }

        public void Aggregate(object dataObject)
        {
            if (!_isAggregating)
            {
                Initialize();
                _isAggregating = true;
            }

            PropertyDescriptor property;
            object value;

            if (dataObject != null && _dataMember != null)
            {
                value = Utils.DataBinderUtil.Eval(dataObject, _dataMember, out property);
                _property = property;
            }
            else
            {
                property = null;
                value = null;
            }

            Aggregate(value, dataObject, property);
        }

        protected abstract void Aggregate(object value, object dataObject, PropertyDescriptor property);

        protected virtual void Initialize()
        {
        }

        protected abstract object FinishAggregate();

        public object Complete()
        {
            _result = FinishAggregate();

            return _result;
        }

        private object _result;

        public object Result
        {
            get { return _result; }
        }

        public static AggregationContext Create(AggregationFunction function, string dataMember)
        {

            switch (function)
            {
                case AggregationFunction.None:
                    return null;
                case AggregationFunction.Sum:
                    return new Sum(dataMember);
                case AggregationFunction.Min:
                    return new Min(dataMember);
                case AggregationFunction.Max:
                    return new Max(dataMember);
                case AggregationFunction.AverageAll:
                case AggregationFunction.AverageValues:
                    Average average = new Average(dataMember);
                    if (function == AggregationFunction.AverageAll)
                        average.CountNullValues = true;
                    return average;
                case AggregationFunction.CountAll:
                case AggregationFunction.CountValues:
                    Count count = new Count(dataMember);
                    if (function == AggregationFunction.CountAll)
                        count.CountNullValues = true;
                    return count;
                default:
                    throw new ArgumentException();
            }
        }
    }
}
